package com.example.mq1.common;

import com.example.mq1.mqserver.core.Binding;
import com.example.mq1.mqserver.core.ExchangeType;
import com.example.mq1.mqserver.core.Message;

public class Router {

    public boolean checkRoutingKey(String routingKey) {
        if(routingKey.length() == 0) {
            //当交换机类型是 fanout 时，routingKey 就没有意义
            return true;
        }
        for(int i = 0; i < routingKey.length(); i++) {
            char ch = routingKey.charAt(i);
            if(ch >= '0' && ch <= '9') {
                continue;
            }
            if(ch >= 'a' && ch <= 'z') {
                continue;
            }
            if(ch >= 'A' && ch <= 'Z') {
                continue;
            }
            if(ch == '_' || ch == '.') {
                continue;
            }
            return false;
        }
        return true;
    }

    public boolean checkBindingKey(String bindingKey) {
        if(bindingKey.length() == 0) {
            //当交换机类型是 fanout / direct(bindingKey 就是队列名) ，bindingKey 就没有意义
            return true;
        }
        for(int i = 0; i < bindingKey.length(); i++) {
            char ch = bindingKey.charAt(i);
            if(ch >= '0' && ch <= '9') {
                continue;
            }
            if(ch >= 'a' && ch <= 'z') {
                continue;
            }
            if(ch >= 'A' && ch <= 'Z') {
                continue;
            }
            if(ch == '_' || ch == '.' || ch == '*' || ch == '#') {
                continue;
            }
            return false;
        }

        String[] words = bindingKey.split("\\.");
        //当一组中长度大于 1，并且存在 * 或者 # 时，就判定为错误
        for(String word : words) {
            if(word.length() > 1 && (word.contains("*") || word.contains("#"))) {
                return false;
            }
        }

        //这里我们约定：相邻关系
        //aaa.#.#.bbb 非法
        //aaa.*.#.bbb 非法
        //aaa.#.*.bbb 非法
        //aaa.*.*.bbb 合法
        for(int i = 0; i < words.length - 1; i++) {
            if(words[i].equals("#") && words[i + 1].equals("#")) {
                return false;
            }
            if(words[i].equals("*") && words[i + 1].equals("#")) {
                return false;
            }
            if(words[i].equals("#") && words[i + 1].equals("*")) {
                return false;
            }
        }
        return true;
    }

    /**
     * Fanout 和 Topic 的匹配规则
     * @param exchangeType
     * @param binding
     * @param message
     * @return
     */
    public boolean route(ExchangeType exchangeType, Binding binding, Message message) throws MqException {
        if(exchangeType == ExchangeType.FANOUT) {
            //这里已经实现了 fanout，直接返回 true 即可
            return true;
        } else if(exchangeType == ExchangeType.TOPIC) {
            return routeTopic(binding, message);
        } else {
            throw new MqException("[Router] 交换机类型非法！ exchangeType=" + exchangeType);
        }
    }

    /**
     * 主题交换机的匹配规则(routingKey 和 bindingKey 匹配)
     * 双指针
     * @param binding
     * @param message
     * @return
     */
    private boolean routeTopic(Binding binding, Message message) {
        String[] bindingTokens = binding.getBindingKey().split("\\.");
        String[] routingTokens = message.getRoutingKey().split("\\.");
        //双指针
        int bindingIndex = 0;
        int routingIndex = 0;
        while(bindingIndex < bindingTokens.length && routingIndex < routingTokens.length) {
            if(bindingTokens[bindingIndex].equals("*")) {
                //直接匹配下一组
                bindingIndex++;
                routingIndex++;
            } else if(bindingTokens[bindingIndex].equals("#")) {
                //如果 # 后面没有下一组了，直接返回true
                bindingIndex++;
                if(bindingIndex == bindingTokens.length) {
                    return true;
                }
                //如果存在下一组，就用下一组去 routingTokens 中寻找匹配的字符串
                int nextIndex = fundNextIndex(routingIndex, routingTokens, bindingTokens[bindingIndex]);
                if(nextIndex == -1) {
                    return false;
                }
                //继续匹配下一组
                bindingIndex++;
                routingIndex = nextIndex + 1;
            } else {
                //普通字符串
                if(!bindingTokens[bindingIndex].equals(routingTokens[routingIndex])) {
                    return false;
                }
                bindingIndex++;
                routingIndex++;
            }
        }
        //判断是否双方都同时到达末尾，如果没有，就返回 false
        return (routingIndex == routingTokens.length && bindingIndex == bindingTokens.length);
    }

    private int fundNextIndex(int routingIndex, String[] routingTokens, String bindingToken) {
        for(int i = routingIndex + 1; i < routingTokens.length; i++) {
            if(routingTokens[i].equals(bindingToken)) {
                return i;
            }
        }
        return -1;
    }
}
